package com.sql.mysql.sharding.session;

import java.io.Serializable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import org.apache.ibatis.session.SqlSession;

import com.sql.mysql.sharding.mapper.ShardingTransactionMapperProxy;

public class ShardingTransactionSqlSessionProxy implements InvocationHandler, Serializable {

	private static final long serialVersionUID = -555649384761687656L;
	private SqlSession sqlSession;

	public ShardingTransactionSqlSessionProxy(SqlSession s) {
		this.sqlSession = s;
	}

	@SuppressWarnings("rawtypes")
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		// 如果是执行普通的方法,比如toString(),比如触发日志打印就会失败
		{
			if (Object.class.equals(method.getDeclaringClass())) {
				return method.invoke(this, args);
			}
		}
		// 如果是业务方法,只能让业务使用getMaper方法,其它一律不容许
		if (false == method.getName().equals("getMapper")) {
			throw new Exception("as a business developer, u can just use getMapper method");
		}
		Object result = method.invoke(sqlSession, args);
		// 作为1个Mapper,同时也需要做代理,就是为了拦截方法获得真实的参数,这是为了用户体验做出的牺牲
		// 我也不想用多个代理,如果你有更好的解决方案,请告诉我
		// 拿到了mapper,做一层代理
		Class targetMapperClass = (Class) args[0];
		return Proxy.newProxyInstance(targetMapperClass.getClassLoader(), new Class[] { targetMapperClass }, //
				new ShardingTransactionMapperProxy(result));
	}
}
